/*
EP3D is a real-time 3D planet engine , which in addition to providing 
substandard scene rendering and scene management, of course, it also 
provides some basic class libraries to build the entire virtual 
planet, or even the entire universe.

Copyright (C) 2010  Hongjiang Zhang	(zhjwyat@gmail.com)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef EP3D_RTTI_H
#define EP3D_RTTI_H
#include "EP3DBase.h"

namespace EP3D
{
	class EP3DEXPORT Rtti
	{
	public:
		Rtti(const char* pcClassName, const Rtti* pkBaseRtti);

		const char* GetName() const { return m_pcClassName; }
		const Rtti* GetBaseRtti() const { return m_pkBaseRtti; }

	private:
		const char* m_pcClassName;
		const Rtti* m_pkBaseRtti;
	};


#define DeclareRootRtti(classname) \
public: \
	static const Rtti ms_Rtti; \
	virtual const Rtti* GetRtti() const { return &ms_Rtti; } \
	static bool IsA(const Rtti* pkRtti, const classname* pkObject) \
	{ \
		if (!pkObject) \
		{ \
			return false; \
		} \
		return pkObject->IsA(pkRtti); \
	} \
	bool IsA(const Rtti* pkRtti) const \
	{ \
		return (GetRtti() == pkRtti); \
	} \
	static bool IsKindOf(const Rtti* pkRtti, const classname* pkObject) \
	{ \
		if (!pkObject) \
		{ \
			return false; \
		} \
		return pkObject->IsKindOf(pkRtti); \
	}\
	bool IsKindOf(const Rtti* pkRtti) const \
	{ \
		const Rtti* pkTemp = GetRtti(); \
		while (pkTemp) \
		{ \
			if (pkTemp == pkRtti) \
			{ \
				return true; \
			} \
			pkTemp = pkTemp->GetBaseRtti(); \
		} \
		return false; \
	} \
	classname* DynamicCast(const Rtti* pkRtti) const \
	{ \
	 	return IsA(pkRtti) ? (classname*)this : 0; \
	} \
	static classname* DynamicCast(const Rtti* pkRtti, const classname* pkObject) \
	{ \
		if (!pkObject) \
		{ \
			return NULL; \
		} \
		return pkObject->DynamicCast(pkRtti); \
	} 

#define DeclareRtti \
	public: \
	static const Rtti ms_Rtti; \
	virtual const Rtti* GetRtti() const { return &ms_Rtti; }

#define ImplementRootRtti(classname) \
	const Rtti classname::ms_Rtti(#classname, 0)

#define ImplementRtti(classname, baseclassname) \
	const Rtti classname::ms_Rtti(#classname, &baseclassname::ms_Rtti)

#define IsInstanceOf(classname, pkObject) \
	classname::IsA(&classname::ms_Rtti, pkObject)
 
#define IsDerivedFrom(classname, pkObject) \
	classname::IsKindOf(&classname::ms_Rtti, pkObject)
 
#define Dynamic_Cast(classname, pkObject) \
	classname::DynamicCast(&classname::ms_Rtti, pkObject)
 
#define Static_Cast(classname, pkObject) \
	((classname*)pkObject)

}//end namespace

#endif